/*
 * @QueueDumper.java 2008/07/28
 *
 * Copyright 2008 Web & Zen Multimedia, All rights reserved.
 * Use is subject to license terms.
 */
package it.wzm.lightweightlog;


import java.util.LinkedList;
import java.util.Properties;


/**
 * This class will retrieve the Entry from the Queue and dispatch to Register
 */
final class QueueDumper extends LightweightlogObject implements Runnable {

	/**
	 * The interval before we dump
	 */
	private long dumpInterval;
	/**
	 * Our queue
	 */
    private Queue<? extends Entry> q;
    /**
     * Our register
     */
    private Register<? extends Dumper> r;
	   

	/**
     * Build a Queue Dumper 
     * @param p Custom set of property
     */
    public QueueDumper(Properties p) {
    	super("queuedumper",p);

        //this.init(p);
        this.setStatus(Status.RUNNING);
    	
    	try {
	        // looking for dump interval
    		String di = this.get("dumpinterval");
	        if (di!=null) {
	            this.dumpInterval = Long.parseLong(di);
	
	            // however by default we cannot dump less then 1 second
	            if (this.dumpInterval < 1000)
	                this.dumpInterval = DEFAULT_DUMP_INTERVAL;
	        } else {
	            this.dumpInterval = DEFAULT_DUMP_INTERVAL;
	        }
	        
    	} catch (Exception e) {
    		throw new LightweightlogInitializationException(e);
    	}
    }
    
    /**
     * Implementing the run() method 
     */
    public void run() {
    	
        // these are needed by our QueueDumper        
        q = LogFactory.getQueue();
        r = LogFactory.getRegister();    

		// we cannot start a QueueDumper when register does not contain Dumper
        // or the Queue is not cumulable, this check is done by the LogFactory first
        // but another check is made now...
        if (!q.isCumulable() || r.size() < 1) {
            return;
        }
        
        try {
            // just a loop
            while (this.getStatus() != Status.SHUTDOWN) {
            	// let's start...
            	this.setStatus(Status.RUNNING);
            	
                // get queue and a list of Entry
            	LinkedList<? extends Entry> l = q.unload();
            	
                // basic check if our queue
                // does contain any Entry...
                if (l!=null && !l.isEmpty()) {
                	r.dispatchToDumper(l);
                    // clear entry from the list...
                    l.clear();
                    // why we 'null' variable ?
                    // Because this may be the case of an Invisible reference
                    // setting to null will help the jvm to gc it...
                    l=null;
                }
             
                // just pausing a while...before retrying
                this.setStatus(Status.SLEEPING);
                Thread.sleep(dumpInterval);
            }

        } catch (QueueException e) {
        	this.setChanged();
        	this.notifyObservers(new QueueDumperException(e.getMessage()));
        	this.setStatus(Status.FAILURE);
        } catch (InterruptedException e) {
        	this.setChanged();
        	this.notifyObservers(new QueueDumperException(e.getMessage()));
            this.setStatus(Status.FAILURE);
        }
    }

    /**
     * Shutdown QueueDumper
     */
	public void kill() {
		// just a limit
		int counter=0;
		
		shutdown:
		while (true) {
			try {				
				// when we asked for shutdown
				// if we are not able to stop the thread
				// within 10 tentatives we run an exception...
				if (counter > 10 ) {
					throw new RuntimeException("Cannot stop the QueueDumper");
				}
				
				if (this.getStatus()==Status.SLEEPING) {
					// set shutdown status...and exit					
					this.setStatus(Status.SHUTDOWN);
					break shutdown;
				} else {
					Thread.sleep(1000);
				}				
				counter++; // trying to arrive to ten...
				
			} catch (InterruptedException e) {
				break shutdown;
			}
		}
	}    	


	/**
	 * Current dump interval
	 * @return long
	 */
	public long getDumpInterval() {
		return this.dumpInterval;
	}
}
